/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.kramerius.rukopisyimport.sourceData;

import cz.mzk.kramerius.commons.Dom4jUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.XPath;

/**
 *
 * @author Martin Rehanek (rehan@mzk.cz)
 */
public class SignatureSysnoMapper {

    private final Map<String, String> signatureSysnoMap = new HashMap<String, String>();
    private static final Logger logger = Logger.getLogger(SignatureSysnoMapper.class.getName());
    private final XPath recordsXpath = DocumentHelper.createXPath("/mappings/record");
    private final XPath idXpath = DocumentHelper.createXPath("id");
    private final XPath baseXpath = DocumentHelper.createXPath("base");
    private final XPath sysnoXpath = DocumentHelper.createXPath("sysno");
    private final XPath signatureXpath = DocumentHelper.createXPath("signature");
    private final String alephBase;
    private final File mappingFile;

    public static SignatureSysnoMapper instanceOf(File mappingfile, String alephBase) {
        try {
            return new SignatureSysnoMapper(mappingfile, alephBase);
        } catch (DocumentException ex) {
            logger.log(Level.SEVERE, null, ex);
            return null;
        } catch (FileNotFoundException ex) {
            logger.log(Level.SEVERE, null, ex);
            return null;
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
            return null;
        }
    }

    private SignatureSysnoMapper(File mappingXml, String alephBase) throws DocumentException, FileNotFoundException, IOException {
        this.alephBase = alephBase;
        this.mappingFile = mappingXml;
        loadMappingFromFile();
    }

    private void loadMappingFromFile() throws DocumentException, FileNotFoundException, IOException {
        Document doc = Dom4jUtils.loadDocument(mappingFile, false);
        List<Element> records = recordsXpath.selectNodes(doc);
        warnIfEmpty(records, "record");
        for (Element recordEl : records) {
            addToMapping(recordEl);
        }
    }

    private void warnIfEmpty(List<Element> elements, String elementName) {
        if (elements.isEmpty()) {
            logger.log(Level.WARNING, "no {0} element", elementName);
        }
    }

    private void addToMapping(Element recordEl) {
        Element idEl = (Element) idXpath.selectSingleNode(recordEl);
        String base = findBase(idEl);
        if (alephBase.equals(base)) {
            String sysno = findSysno(idEl);
            String signature = findSignature(recordEl);
            addIfNotPresent(sysno, signature);
        } else {
            logger.log(Level.WARNING, "found base {0} differs from required base {1}", new Object[]{base, alephBase});
        }
    }

    private String findBase(Element idEl) {
        Element baseEl = (Element) baseXpath.selectSingleNode(idEl);
        return baseEl.getTextTrim();
    }

    private String findSysno(Element idEl) {
        Element sysnoEl = (Element) sysnoXpath.selectSingleNode(idEl);
        return sysnoEl.getTextTrim();
    }

    private String findSignature(Element recordEl) {
        Element signatureEl = (Element) signatureXpath.selectSingleNode(recordEl);
        return signatureEl.getTextTrim();
    }

    private void addIfNotPresent(String sysno, String signature) {
        String sysnoFound = signatureSysnoMap.get(signature);
        if (sysnoFound == null) {
            signatureSysnoMap.put(signature, sysno);
            logger.log(Level.INFO, "adding mapping {0},{1}:{2}", new Object[]{alephBase, sysno, signature});
        } else {
            logger.log(Level.WARNING, "sysno already present for signature {0}. Found {1}, wanted to add {2}", new Object[]{signature, sysnoFound, sysno});
        }
    }

    public int getSize() {
        return signatureSysnoMap.size();
    }

    public String getSysno(String signature) {

        return signatureSysnoMap.get(signature);
    }
}
